from django.db import models
from django.contrib.auth.models import User, Group
from django.utils import timezone
from django.db.models.signals import post_save
from django.dispatch import receiver
import json
import paramiko
import traceback


class UserProfile(models.Model):
    """用户扩展信息"""
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    chinese_name = models.CharField(verbose_name='中文名', max_length=50, blank=True, null=True)
    avatar = models.ImageField(verbose_name='头像', upload_to='avatars/', blank=True, null=True)

    def __str__(self):
        return f"{self.user.username} - {self.chinese_name or '未设置中文名'}"

    class Meta:
        verbose_name = '用户资料'
        verbose_name_plural = '用户资料'


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """创建用户时自动创建对应的profile"""
    if created:
        UserProfile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    """保存用户时自动保存对应的profile"""
    try:
        if hasattr(instance, 'profile'):
            instance.profile.save()
    except Exception as e:
        print(f"保存用户profile时出错: {e}")
        # 如果profile不存在，创建一个
        UserProfile.objects.get_or_create(user=instance)


class UserGroup(models.Model):
    """用户组"""
    GROUP_CHOICES = (
        ('dev', '开发组'),
        ('ops', '运维组'),
        ('test', '测试组'),
        ('product', '产品组'),
    )

    name = models.CharField(verbose_name='组名', max_length=50)
    code = models.CharField(verbose_name='编码', max_length=20, choices=GROUP_CHOICES, unique=True)
    description = models.TextField(verbose_name='描述', blank=True, null=True)
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '用户组'
        verbose_name_plural = '用户组'


class UserRole(models.Model):
    """用户角色"""
    ROLE_LEVEL_CHOICES = (
        (1, '普通成员'),
        (2, '组长'),
        (3, '总监'),
    )

    name = models.CharField(verbose_name='角色名', max_length=50)
    group = models.ForeignKey(UserGroup, verbose_name='所属组', on_delete=models.CASCADE, related_name='roles')
    level = models.IntegerField(verbose_name='级别', choices=ROLE_LEVEL_CHOICES, default=1)
    description = models.TextField(verbose_name='描述', blank=True, null=True)
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True)

    class Meta:
        verbose_name = '用户角色'
        verbose_name_plural = '用户角色'
        unique_together = ('group', 'level')  # 确保每个组的每个级别只有一个角色

    def __str__(self):
        return f"{self.group.name}-{self.name}"


class UserGroupRole(models.Model):
    """用户-组-角色关联"""
    user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE, related_name='group_roles')
    group = models.ForeignKey(UserGroup, verbose_name='用户组', on_delete=models.CASCADE, related_name='user_roles')
    role = models.ForeignKey(UserRole, verbose_name='角色', on_delete=models.CASCADE, related_name='user_assignments')
    is_primary = models.BooleanField(verbose_name='是否主要组/角色', default=False)
    created_at = models.DateTimeField(verbose_name='分配时间', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True)

    class Meta:
        verbose_name = '用户组角色关联'
        verbose_name_plural = '用户组角色关联'
        unique_together = ('user', 'group')  # 确保一个用户在一个组中只有一个角色

    def __str__(self):
        return f"{self.user.username} - {self.group.name} - {self.role.name}"


class HostType(models.Model):
    """主机类型模型"""
    name = models.CharField(max_length=50, unique=True, verbose_name="类型名称")
    display_name = models.CharField(max_length=100, verbose_name="显示名称")
    icon = models.CharField(max_length=50, verbose_name="图标类名", help_text="FontAwesome图标类名，如：fa-server")
    color = models.CharField(max_length=20, verbose_name="颜色", help_text="十六进制颜色值，如：#409eff")
    description = models.TextField(blank=True, verbose_name="描述")
    is_system = models.BooleanField(default=False, verbose_name="系统内置", help_text="系统内置类型不可删除")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        db_table = 'cmdb_host_type'
        verbose_name = '主机类型'
        verbose_name_plural = '主机类型'
        ordering = ['name']

    def __str__(self):
        return self.display_name


class HostGroup(models.Model):
    """主机组模型"""
    ENVIRONMENT_CHOICES = (
        ('dev', '开发环境'),
        ('test', '测试环境'),
        ('staging', '预发布环境'),
        ('prod', '生产环境'),
    )

    name = models.CharField(verbose_name='主机组名称', max_length=100)
    ansible_name = models.CharField(verbose_name='Ansible名称', max_length=100, blank=True, null=True, help_text='用于Ansible的英文名称，如果为空则自动生成')
    description = models.TextField(verbose_name='描述', blank=True, null=True)
    environment = models.CharField(verbose_name='环境', max_length=20, choices=ENVIRONMENT_CHOICES, default='dev')
    owner = models.ForeignKey(User, verbose_name='负责人', on_delete=models.SET_NULL, null=True, blank=True, related_name='owned_host_groups')
    tags = models.CharField(verbose_name='标签', max_length=200, blank=True, null=True, help_text='多个标签用逗号分隔')
    is_active = models.BooleanField(verbose_name='是否启用', default=True)
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True)

    def __str__(self):
        return f"{self.name} ({self.get_environment_display()})"

    def save(self, *args, **kwargs):
        """保存时自动生成ansible_name"""
        if not self.ansible_name:
            self.ansible_name = self.generate_ansible_name()
        super().save(*args, **kwargs)

    def generate_ansible_name(self):
        """生成Ansible兼容的英文名称"""
        # 中文到英文的映射表
        name_mapping = {
            'web服务器组': 'web_servers',
            '数据库组': 'database_servers',
            '文件服务器组': 'file_servers',
            '负载均衡组': 'load_balancers',
            '备份服务器组': 'backup_servers',
            '缓存服务器组': 'cache_servers',
            '应用服务器组': 'app_servers',
            '监控服务器组': 'monitor_servers',
            '日志服务器组': 'log_servers',
            '消息队列组': 'message_queue_servers',
        }

        # 如果有直接映射，使用映射
        if self.name in name_mapping:
            base_name = name_mapping[self.name]
        else:
            # 否则生成基于环境的通用名称
            base_name = f"{self.environment}_group_{self.id or 'new'}"

        return base_name

    @property
    def host_count(self):
        """获取主机数量"""
        return self.hosts.count()

    @property
    def online_host_count(self):
        """获取在线主机数量"""
        return self.hosts.filter(status='online').count()

    class Meta:
        verbose_name = '主机组'
        verbose_name_plural = '主机组'
        ordering = ['-created_at']
        # 在同一环境下主机组名称唯一
        unique_together = [['name', 'environment']]


class Host(models.Model):
    """主机模型"""
    TYPE_CHOICES = (
        ('web', 'Web服务器'),
        ('db', '数据库服务器'),
        ('app', '应用服务器'),
        ('cache', '缓存服务器'),
        ('other', '其他'),
    )
    STATUS_CHOICES = (
        ('online', '在线'),
        ('offline', '离线'),
    )
    AUTH_TYPE_CHOICES = (
        ('password', '密码认证'),
        ('key', '密钥认证'),
    )

    hostname = models.CharField(verbose_name='主机名', max_length=100, unique=True)
    ip = models.GenericIPAddressField(verbose_name='IP地址', null=True, blank=True)
    public_ip = models.GenericIPAddressField(verbose_name='公网IP地址', unique=True)
    private_ip = models.GenericIPAddressField(verbose_name='内网IP地址', blank=True, null=True, unique=True)
    port = models.IntegerField(verbose_name='端口', default=22)
    username = models.CharField(verbose_name='用户名', max_length=100)
    auth_type = models.CharField(verbose_name='认证方式', max_length=20, choices=AUTH_TYPE_CHOICES, default='password')
    password = models.CharField(verbose_name='密码', max_length=300, blank=True, null=True)
    private_key = models.TextField(verbose_name='私钥', blank=True, null=True)
    passphrase = models.CharField(verbose_name='私钥密码', max_length=300, blank=True, null=True)
    type = models.CharField(verbose_name='类型', max_length=20, choices=TYPE_CHOICES, default='other')
    status = models.CharField(verbose_name='状态', max_length=20, choices=STATUS_CHOICES, default='offline')
    # 添加主机组关联
    host_groups = models.ManyToManyField(HostGroup, verbose_name='所属主机组', blank=True, related_name='hosts')
    cpu = models.CharField(verbose_name='CPU', max_length=100, blank=True, null=True)
    memory = models.CharField(verbose_name='内存', max_length=100, blank=True, null=True)
    disk = models.CharField(verbose_name='磁盘', max_length=100, blank=True, null=True)
    os = models.CharField(verbose_name='操作系统', max_length=100, blank=True, null=True)
    cpu_info = models.CharField(verbose_name='CPU信息', max_length=200, blank=True, null=True)
    memory_info = models.CharField(verbose_name='内存信息', max_length=200, blank=True, null=True)
    disk_info = models.CharField(verbose_name='磁盘信息', max_length=200, blank=True, null=True)
    os_version = models.CharField(verbose_name='系统版本', max_length=200, blank=True, null=True)
    system_type = models.CharField(verbose_name='系统类型', max_length=100, blank=True, null=True)
    cpu_arch = models.CharField(verbose_name='CPU架构', max_length=50, blank=True, null=True)
    system_environment = models.CharField(verbose_name='系统环境', max_length=100, blank=True, null=True)
    remark = models.TextField(verbose_name='备注', blank=True, null=True)
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新时间', auto_now=True)

    def __str__(self):
        if self.public_ip:
            return f"{self.hostname} ({self.public_ip})"
        else:
            return f"{self.hostname} ({self.ip or '未知IP'})"

    class Meta:
        verbose_name = '主机'
        verbose_name_plural = '主机'
        ordering = ['-created_at']


class ConnectionRecord(models.Model):
    """主机连接记录"""
    user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE, related_name='connections')
    host = models.ForeignKey(Host, verbose_name='主机', on_delete=models.CASCADE, related_name='connections')
    connected_at = models.DateTimeField(verbose_name='连接时间', default=timezone.now)
    disconnected_at = models.DateTimeField(verbose_name='断开时间', blank=True, null=True)
    last_activity = models.DateTimeField(verbose_name='最后活动时间', default=timezone.now)
    is_active = models.BooleanField(verbose_name='是否活跃', default=True)
    command_count = models.IntegerField(verbose_name='命令数', default=0)

    def __str__(self):
        return f"{self.user.username} -> {self.host.hostname}"

    class Meta:
        verbose_name = '连接记录'
        verbose_name_plural = '连接记录'
        ordering = ['-connected_at']


class CommandLog(models.Model):
    """命令日志"""
    connection = models.ForeignKey(ConnectionRecord, verbose_name='连接记录', on_delete=models.CASCADE, related_name='commands')
    command = models.TextField(verbose_name='命令')
    output = models.TextField(verbose_name='输出', blank=True, null=True)
    executed_at = models.DateTimeField(verbose_name='执行时间', auto_now_add=True)
    # 新增字段，用于存储命令输出的详细时间戳信息
    output_with_timestamps = models.TextField(verbose_name='带时间戳的输出', blank=True, null=True,
                                             help_text='格式为[{"content": "输出内容", "timestamp": "时间戳"}]')
    duration = models.FloatField(verbose_name='执行时长(秒)', blank=True, null=True)
    exit_code = models.IntegerField(verbose_name='退出码', blank=True, null=True)
    # 新增字段用于审计
    input_size = models.IntegerField(verbose_name='输入大小(字节)', default=0)
    output_size = models.IntegerField(verbose_name='输出大小(字节)', default=0)
    is_dangerous = models.BooleanField(verbose_name='是否危险命令', default=False)
    risk_level = models.CharField(verbose_name='风险级别', max_length=10,
                                 choices=[('low', '低'), ('medium', '中'), ('high', '高'), ('critical', '严重')],
                                 default='low')

    def __str__(self):
        return f"{self.connection.user.username} @ {self.connection.host.hostname}: {self.command}"

    def set_output_events(self, events):
        """设置带时间戳的输出事件"""
        if events:
            self.output_with_timestamps = json.dumps(events)
        else:
            self.output_with_timestamps = None

    def get_output_events(self):
        """获取带时间戳的输出事件"""
        if self.output_with_timestamps:
            return json.loads(self.output_with_timestamps)
        return []

    def analyze_risk(self):
        """分析命令风险"""
        dangerous_commands = [
            'rm -rf', 'dd if=', 'mkfs', 'fdisk', 'parted',
            'shutdown', 'reboot', 'halt', 'poweroff',
            'passwd', 'userdel', 'groupdel',
            'iptables -F', 'ufw --force',
            'chmod 777', 'chown -R'
        ]

        critical_commands = [
            'rm -rf /', 'dd if=/dev/zero', 'mkfs.ext4 /dev/',
            'fdisk /dev/', 'parted /dev/'
        ]

        command_lower = self.command.lower()

        for cmd in critical_commands:
            if cmd in command_lower:
                self.risk_level = 'critical'
                self.is_dangerous = True
                return

        for cmd in dangerous_commands:
            if cmd in command_lower:
                self.risk_level = 'high'
                self.is_dangerous = True
                return

        if any(word in command_lower for word in ['sudo', 'su -', 'root']):
            self.risk_level = 'medium'
        else:
            self.risk_level = 'low'

    def save(self, *args, **kwargs):
        # 计算输入输出大小
        self.input_size = len(self.command.encode('utf-8'))
        if self.output:
            self.output_size = len(self.output.encode('utf-8'))

        # 分析风险
        self.analyze_risk()

        super().save(*args, **kwargs)

    class Meta:
        verbose_name = '命令日志'
        verbose_name_plural = '命令日志'
        ordering = ['-executed_at']


class Alert(models.Model):
    """告警记录"""
    LEVEL_CHOICES = (
        ('info', '信息'),
        ('warning', '警告'),
        ('danger', '严重'),
    )
    host = models.ForeignKey(Host, verbose_name='主机', on_delete=models.CASCADE, related_name='alerts')
    title = models.CharField(verbose_name='标题', max_length=200)
    content = models.TextField(verbose_name='内容')
    level = models.CharField(verbose_name='级别', max_length=20, choices=LEVEL_CHOICES, default='info')
    is_read = models.BooleanField(verbose_name='是否已读', default=False)
    created_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    def __str__(self):
        return f"{self.host.hostname}: {self.title}"

    class Meta:
        verbose_name = '告警'
        verbose_name_plural = '告警'
        ordering = ['-created_at']


# 菜单项模型
class MenuItem(models.Model):
    """
    菜单项模型，定义系统中所有可用的菜单项。
    """
    name = models.CharField(max_length=50, verbose_name="菜单名称")
    path = models.CharField(max_length=100, verbose_name="路由路径", unique=True)
    icon = models.CharField(max_length=50, verbose_name="图标", blank=True)
    parent = models.ForeignKey('self', verbose_name="父菜单", on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    order = models.IntegerField(default=0, verbose_name="排序")
    is_enabled = models.BooleanField(default=True, verbose_name="是否启用")

    # 新增字段支持动态菜单管理
    sort_weight = models.FloatField(default=0.0, verbose_name="排序权重", help_text="用于拖拽排序的浮点权重")
    component_name = models.CharField(max_length=100, verbose_name="组件名称", blank=True, help_text="Vue组件名称")
    is_generated = models.BooleanField(default=False, verbose_name="是否自动生成", help_text="是否为系统自动生成的页面")
    description = models.TextField(blank=True, verbose_name="菜单描述", help_text="菜单功能描述")
    permission_code = models.CharField(max_length=100, verbose_name="权限代码", blank=True, help_text="权限控制代码")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = '菜单项'
        verbose_name_plural = '菜单项'
        ordering = ['sort_weight', 'order', 'id']

    def __str__(self):
        return self.name

    def get_full_path(self):
        """获取完整路径"""
        if self.parent:
            return f"{self.parent.get_full_path()}{self.path}"
        return self.path

    def get_children_recursive(self):
        """递归获取所有子菜单"""
        children = []
        for child in self.children.filter(is_enabled=True).order_by('sort_weight', 'order'):
            children.append({
                'id': child.id,
                'name': child.name,
                'path': child.path,
                'icon': child.icon,
                'sort_weight': child.sort_weight,
                'component_name': child.component_name,
                'is_generated': child.is_generated,
                'permission_code': child.permission_code,
                'children': child.get_children_recursive()
            })
        return children


# 用户组菜单权限关联
class GroupMenuPermission(models.Model):
    """
    用户组与菜单项的权限关联表。
    """
    group = models.ForeignKey(Group, verbose_name="用户组", on_delete=models.CASCADE, related_name='menu_permissions')
    menu_item = models.ForeignKey(MenuItem, verbose_name="菜单项", on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    class Meta:
        verbose_name = '用户组菜单权限'
        verbose_name_plural = '用户组菜单权限'
        unique_together = ('group', 'menu_item')

    def __str__(self):
        return f"{self.group.name} - {self.menu_item.name}"


# SSH审计相关模型
class SSHSession(models.Model):
    """SSH会话记录"""
    SESSION_STATUS_CHOICES = [
        ('active', '活跃'),
        ('closed', '已关闭'),
        ('timeout', '超时'),
        ('error', '错误'),
    ]

    session_id = models.CharField(max_length=64, unique=True, verbose_name='会话ID')
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
    host = models.ForeignKey(Host, on_delete=models.CASCADE, verbose_name='主机')

    # 连接信息
    client_ip = models.GenericIPAddressField(verbose_name='客户端IP', null=True, blank=True)
    user_agent = models.TextField(blank=True, verbose_name='用户代理')

    # 会话状态
    status = models.CharField(max_length=20, choices=SESSION_STATUS_CHOICES, default='active', verbose_name='状态')
    start_time = models.DateTimeField(auto_now_add=True, verbose_name='开始时间')
    end_time = models.DateTimeField(null=True, blank=True, verbose_name='结束时间')
    duration = models.IntegerField(default=0, verbose_name='持续时间(秒)')

    # 统计信息
    command_count = models.IntegerField(default=0, verbose_name='命令数量')
    data_size = models.BigIntegerField(default=0, verbose_name='数据大小(字节)')

    # 审计文件路径
    log_file_path = models.CharField(max_length=500, blank=True, verbose_name='日志文件路径')
    replay_file_path = models.CharField(max_length=500, blank=True, verbose_name='回放文件路径')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'ssh_session'
        verbose_name = 'SSH会话'
        verbose_name_plural = 'SSH会话'
        ordering = ['-start_time']

    def __str__(self):
        return f"{self.user.username}@{self.host.hostname} ({self.session_id})"


class SSHCommand(models.Model):
    """SSH命令记录"""
    COMMAND_TYPE_CHOICES = [
        ('input', '输入'),
        ('output', '输出'),
        ('system', '系统'),
    ]

    RISK_LEVEL_CHOICES = [
        ('low', '低风险'),
        ('medium', '中风险'),
        ('high', '高风险'),
        ('critical', '严重'),
    ]

    session = models.ForeignKey(SSHSession, on_delete=models.CASCADE, related_name='commands', verbose_name='会话')

    # 命令信息
    command_type = models.CharField(max_length=20, choices=COMMAND_TYPE_CHOICES, verbose_name='命令类型')
    command = models.TextField(verbose_name='命令内容')
    output = models.TextField(blank=True, verbose_name='命令输出')

    # 执行信息
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name='执行时间')
    duration = models.FloatField(default=0, verbose_name='执行耗时(秒)')
    exit_code = models.IntegerField(null=True, blank=True, verbose_name='退出码')

    # 风险评估
    risk_level = models.CharField(max_length=20, choices=RISK_LEVEL_CHOICES, default='low', verbose_name='风险等级')
    is_dangerous = models.BooleanField(default=False, verbose_name='是否危险命令')

    # 审计信息
    working_directory = models.CharField(max_length=500, blank=True, verbose_name='工作目录')
    environment_vars = models.JSONField(default=dict, blank=True, verbose_name='环境变量')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        db_table = 'ssh_command'
        verbose_name = 'SSH命令'
        verbose_name_plural = 'SSH命令'
        ordering = ['-timestamp']
        indexes = [
            models.Index(fields=['session', 'timestamp']),
            models.Index(fields=['command_type', 'timestamp']),
            models.Index(fields=['risk_level']),
        ]

    def __str__(self):
        return f"{self.session.user.username}: {self.command[:50]}"


class SSHReplayData(models.Model):
    """SSH回放数据"""
    session = models.ForeignKey(SSHSession, on_delete=models.CASCADE, related_name='replay_data', verbose_name='会话')

    # 回放数据
    timestamp = models.FloatField(verbose_name='时间戳(相对于会话开始)')
    data_type = models.CharField(max_length=20, verbose_name='数据类型')  # input, output, resize
    data = models.TextField(verbose_name='数据内容')

    # 终端信息
    terminal_width = models.IntegerField(default=80, verbose_name='终端宽度')
    terminal_height = models.IntegerField(default=24, verbose_name='终端高度')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        db_table = 'ssh_replay_data'
        verbose_name = 'SSH回放数据'
        verbose_name_plural = 'SSH回放数据'
        ordering = ['timestamp']
        indexes = [
            models.Index(fields=['session', 'timestamp']),
        ]


class AuditRule(models.Model):
    """审计规则"""
    RULE_TYPE_CHOICES = [
        ('command', '命令规则'),
        ('keyword', '关键词规则'),
        ('pattern', '模式规则'),
    ]

    ACTION_CHOICES = [
        ('log', '记录日志'),
        ('alert', '发送告警'),
        ('block', '阻止执行'),
    ]

    name = models.CharField(max_length=100, verbose_name='规则名称')
    description = models.TextField(blank=True, verbose_name='规则描述')

    # 规则配置
    rule_type = models.CharField(max_length=20, choices=RULE_TYPE_CHOICES, verbose_name='规则类型')
    pattern = models.TextField(verbose_name='匹配模式')
    is_regex = models.BooleanField(default=False, verbose_name='是否正则表达式')
    case_sensitive = models.BooleanField(default=True, verbose_name='大小写敏感')

    # 动作配置
    action = models.CharField(max_length=20, choices=ACTION_CHOICES, verbose_name='触发动作')
    risk_level = models.CharField(max_length=20, choices=SSHCommand.RISK_LEVEL_CHOICES, default='medium', verbose_name='风险等级')

    # 状态
    is_active = models.BooleanField(default=True, verbose_name='是否启用')
    priority = models.IntegerField(default=0, verbose_name='优先级')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'audit_rule'
        verbose_name = '审计规则'
        verbose_name_plural = '审计规则'
        ordering = ['-priority', 'name']

    def __str__(self):
        return self.name


class AuditAlert(models.Model):
    """审计告警"""
    ALERT_STATUS_CHOICES = [
        ('pending', '待处理'),
        ('confirmed', '已确认'),
        ('ignored', '已忽略'),
        ('resolved', '已解决'),
    ]

    session = models.ForeignKey(SSHSession, on_delete=models.CASCADE, verbose_name='会话')
    command = models.ForeignKey(SSHCommand, on_delete=models.CASCADE, verbose_name='命令')
    rule = models.ForeignKey(AuditRule, on_delete=models.CASCADE, verbose_name='触发规则')

    # 告警信息
    title = models.CharField(max_length=200, verbose_name='告警标题')
    description = models.TextField(verbose_name='告警描述')
    risk_level = models.CharField(max_length=20, choices=SSHCommand.RISK_LEVEL_CHOICES, verbose_name='风险等级')

    # 处理状态
    status = models.CharField(max_length=20, choices=ALERT_STATUS_CHOICES, default='pending', verbose_name='处理状态')
    handler = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='handled_alerts', verbose_name='处理人')
    handle_time = models.DateTimeField(null=True, blank=True, verbose_name='处理时间')
    handle_note = models.TextField(blank=True, verbose_name='处理备注')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        db_table = 'audit_alert'
        verbose_name = '审计告警'
        verbose_name_plural = '审计告警'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.title} - {self.session.user.username}"


# ==================== 角色权限系统模型 ====================

class Role(models.Model):
    """角色模型"""
    name = models.CharField(max_length=50, unique=True, verbose_name='角色名称')
    description = models.TextField(blank=True, null=True, verbose_name='角色描述')
    is_system = models.BooleanField(default=False, verbose_name='系统预设角色')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'cmdb_role'
        verbose_name = '角色'
        verbose_name_plural = '角色'
        indexes = [
            models.Index(fields=['name'], name='cmdb_role_name_idx'),
        ]

    def __str__(self):
        return self.name

    def get_menu_permissions(self):
        """获取角色的菜单权限"""
        return RoleMenuPermission.objects.filter(role=self)

    def has_menu_permission(self, menu_item, permission_type='read'):
        """检查角色是否有指定菜单的权限"""
        try:
            perm = RoleMenuPermission.objects.get(role=self, menu_item=menu_item)
            if permission_type == 'read':
                return perm.can_read
            elif permission_type == 'write':
                return perm.can_write
            return False
        except RoleMenuPermission.DoesNotExist:
            return False


class GroupRole(models.Model):
    """用户组角色关联"""
    group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name='用户组')
    role = models.ForeignKey(Role, on_delete=models.CASCADE, verbose_name='角色')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        db_table = 'cmdb_group_role'
        unique_together = ('group', 'role')
        verbose_name = '用户组角色关联'
        verbose_name_plural = '用户组角色关联'
        indexes = [
            models.Index(fields=['group'], name='cmdb_group_role_group_idx'),
        ]

    def __str__(self):
        return f'{self.group.name} - {self.role.name}'


class RoleMenuPermission(models.Model):
    """角色菜单权限"""
    role = models.ForeignKey(Role, on_delete=models.CASCADE, verbose_name='角色')
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE, verbose_name='菜单项')
    can_read = models.BooleanField(default=True, verbose_name='可读权限')
    can_write = models.BooleanField(default=False, verbose_name='可写权限')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')

    class Meta:
        db_table = 'cmdb_role_menu_permission'
        unique_together = ('role', 'menu_item')
        verbose_name = '角色菜单权限'
        verbose_name_plural = '角色菜单权限'
        indexes = [
            models.Index(fields=['role'], name='cmdb_role_menu_role_idx'),
        ]

    def __str__(self):
        permissions = []
        if self.can_read:
            permissions.append('读')
        if self.can_write:
            permissions.append('写')
        return f'{self.role.name} - {self.menu_item.name} ({"/".join(permissions)})'
